package com.victualler.core.common.utils;


import com.victualler.core.common.dto.JasperReportVO;
import com.victualler.core.common.enums.ChecKDataErrorEnum;
import com.victualler.core.common.enums.JasperTypeEnum;
import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.base.JRBaseReport;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.export.JRHtmlExporter;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import net.sf.jasperreports.engine.export.ooxml.JRDocxExporter;
import net.sf.jasperreports.engine.export.ooxml.JRXlsxExporter;
import net.sf.jasperreports.engine.util.JRLoader;
import net.sf.jasperreports.export.*;
import org.springframework.core.io.ClassPathResource;

import java.io.*;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Aouthor Guoshichang
 * @Date 11:50 on 2018/7/16.
 * @Function 用于组织IReport数据,用于输出iReport对应的 pdf,html,excel等内容
 */
public class ReportUtil {

    /**
     * @author Guoshichang
     * @since 12:03 on 2018/7/16.
     * @param filePath 文件保存路径
     * @param jasperReportVO Jasper导出对象
     * @Function
     */
    public static File savePdfByPath(String filePath, JasperReportVO jasperReportVO){
        FileOutputStream out = null;
        try {
            File file = new File(filePath);
            if(!file.getParentFile().exists()){
                file.getParentFile().mkdirs();
            }
            out =  new FileOutputStream(file);
            List<JasperReportVO> jasperReportVOList = new ArrayList<>();
            jasperReportVOList.add(jasperReportVO);
            //调用底层逻辑进行转换
            ReportUtil.reportData(jasperReportVOList,null, JasperTypeEnum.PDF, out);
            return file;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            throw ChecKDataErrorEnum.createException(ChecKDataErrorEnum.RUN_ERROR,e.getMessage());
        }finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * @author LiChong
     * @since 11:50 on 2018/7/20.
     * @param jasperReportVO Jasper导出对象
     * @param outputStream 输出流
     * @Function 生成单Sheet页Excel至流
     */
    public static void genXlsForOneSheet(JasperReportVO jasperReportVO, OutputStream outputStream) {
        List<JasperReportVO> jasperReportVOList = new ArrayList<>();
        jasperReportVOList.add(jasperReportVO);
        ReportUtil.genXlsForMultSheet(jasperReportVOList,outputStream);
    }

    /**
     * @author LiChong
     * @since 11:50 on 2018/7/20.
     * @param jasperReportVOList Jasper导出对象数组
     * @param outputStream 输出流
     * @Function 生成多Sheet页Excel至流
     */
    public static void genXlsForMultSheet(List<JasperReportVO> jasperReportVOList, OutputStream outputStream) {
        String[] sheetNames = new String[jasperReportVOList.size()];
        for (int i = 0; i < jasperReportVOList.size(); i++) {
            sheetNames[i] = jasperReportVOList.get(i).getSheetName();
        }
        //excel的配置
        SimpleXlsReportConfiguration config = getCommonXlsConfigBySheetNames(sheetNames);
        ReportUtil.reportData(jasperReportVOList,config, JasperTypeEnum.EXCEL_XLS, outputStream);
    }


    /**
     * @author LiChong
     * @since 17:00 on 2018/7/21.
     * @param jasperReportVOList 模板对象导出列表
     * @param reportExportConfiguration 配置对象
     * @param exportType 文件枚举类型
     * @param outputStream 输出流
     * @Function 底层通用方法, 可以根据 exportType 导出不同类型的文件
     */
    public static void reportData(List<JasperReportVO>  jasperReportVOList,ReportExportConfiguration reportExportConfiguration, JasperTypeEnum exportType, OutputStream outputStream) {
        try {
            //根据文件类型获取对应的Exporter导出模板对象
            JRAbstractExporter exporter = getByExportType(exportType);
            //设置数据源
            List<JasperPrint> jasperPrintList = new ArrayList<JasperPrint>();
            //合并多个模板
            jasperReportVOList.forEach(jasperReportVO ->{
                //将JasperReportVO对象转换为JasperPrint对象
                JasperPrint jasperPrint = ReportUtil.getJasperPrint(jasperReportVO, exportType);
                jasperPrintList.add(jasperPrint);
            });
            //将多个JasperPrint对象转换合并为数据源对象
            exporter.setExporterInput(SimpleExporterInput.getInstance(jasperPrintList));
            //设置配置文件
            if(reportExportConfiguration!=null){
                exporter.setConfiguration(reportExportConfiguration);
            }
            //设置输出流
            exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(outputStream));
            //将数据输出到Output输出流中
            exporter.exportReport();
        } catch (JRException e) {
            e.printStackTrace();
            throw ChecKDataErrorEnum.createException(ChecKDataErrorEnum.RUN_ERROR,e.getMessage());
        }
    }

    /**
     * @author Guoshichang
     * @since 17:23 on 2018/7/20.
     * @param exportType 文件枚举类型
     * @Function  根据枚举类型匹配对应的pdf导出Export对象
     */
    private static JRAbstractExporter getByExportType(JasperTypeEnum exportType){
        if(exportType.equals(JasperTypeEnum.PDF)){
            return new JRPdfExporter();
        }
        else if(exportType.equals(JasperTypeEnum.EXCEL_XLS)){
            return new JRXlsExporter();
        }
        else if(exportType.equals(JasperTypeEnum.EXCEL_XLSX)){
            return new JRXlsxExporter();
        }
        else if(exportType.equals(JasperTypeEnum.WORD_DOC) || exportType.equals(JasperTypeEnum.WORD_DOCX)){
            return new JRDocxExporter();
        }
        else if(exportType.equals(JasperTypeEnum.HTML)){
            return new JRHtmlExporter();
        }else{
            throw ChecKDataErrorEnum.createException(ChecKDataErrorEnum.CONFIG_ERROR,"未匹配到iReport的模板类型!");
        }
    }



    /**
     * @author Guoshichang
     * @since 14:13 on 2018/7/23.
     * @param sheetNames
     * @Function  获取通用的excel模板对应的配置对象
     */
    private static SimpleXlsReportConfiguration getCommonXlsConfigBySheetNames(String[] sheetNames){
        SimpleXlsReportConfiguration configuration = new SimpleXlsReportConfiguration();
        configuration.setDetectCellType(true);
        configuration.setWhitePageBackground(true);
        configuration.setOnePagePerSheet(true);
        configuration.setRemoveEmptySpaceBetweenRows(true);
        configuration.setSheetNames(sheetNames);
        return configuration;
    }

    /**
     * @author LiChong
     * @since 11:50 on 2018/7/20.
     * @param jasperReportVO Jasper导出对象
     * @param exportType 文件枚举类型
     * @return 获取导出对象
     * @Function 获取导出对象
     */
    private static JasperPrint getJasperPrint(JasperReportVO jasperReportVO, JasperTypeEnum exportType) {
        JasperPrint jasperPrint = null;
        try {
            //处理路径至流
            InputStream jasperPath = new ClassPathResource(jasperReportVO.getJasperClassPath()).getInputStream();
            //将模板数据放置到模板集合中
            JasperReport jasperReport = (JasperReport) JRLoader.loadObject(jasperPath);
            //Excel特殊处理
            if(exportType.equals(JasperTypeEnum.EXCEL_XLS) || exportType.equals(JasperTypeEnum.EXCEL_XLSX)) {
                ReportUtil.setJasperPrintExcelCommonConfig(jasperReport);
            }
            //数据源对象
            JRDataSource jrDataSource = new JRBeanCollectionDataSource(jasperReportVO.getModelList());
            //处理rptParam数据
            Map<String,Object> params = new HashMap<>();
            if(jasperReportVO.getParameter() != null ){
                //javaBean 对象转map
                String json = JsonUtil.toJsonString(jasperReportVO.getParameter(),false);
                params = JsonUtil.toJavaObject(json,Map.class);
            }
            jasperPrint = JasperFillManager.fillReport(jasperReport, params, jrDataSource);
        } catch (Exception e) {
            e.printStackTrace();
            throw ChecKDataErrorEnum.createException(ChecKDataErrorEnum.RUN_ERROR,e.getMessage());
        }

        return jasperPrint;
    }

    /**
     * @author Guoshichang
     * @since 14:58 on 2018/7/23.
     * @param jasperReport 输出对象
     * @Function 配置对应的JasperPrint通用设置
     */
    public static void setJasperPrintExcelCommonConfig(JasperReport jasperReport) throws NoSuchFieldException, IllegalAccessException {
        Field leftMargin = JRBaseReport.class.getDeclaredField("leftMargin");
        Field topMargin = JRBaseReport.class.getDeclaredField("topMargin");
        Field bottomMargin = JRBaseReport.class.getDeclaredField("bottomMargin");
        Field pageHeight = JRBaseReport.class.getDeclaredField("pageHeight");
        leftMargin.setAccessible(true);
        leftMargin.setInt(jasperReport, 0);
        topMargin.setAccessible(true);
        topMargin.setInt(jasperReport, 0);
        bottomMargin.setAccessible(true);
        bottomMargin.setInt(jasperReport, 0);
        if (null != jasperReport.getGroups()) {
            for (int i = 0; i < jasperReport.getGroups().length; i++) {
                jasperReport.getGroups()[i].setReprintHeaderOnEachPage(false);
            }
        }
        pageHeight.setAccessible(true);
        pageHeight.setInt(jasperReport,Integer.MAX_VALUE);
    }



    /**
     * @author Guoshichang
     * @since 17:34 on 2018/7/16.
     * @param args
     * @Function 测试ireport工具导出
     */
    public static void  main(String[] args) throws IOException {
        // 模板数据
//        FacAccountPrintVO a = new FacAccountPrintVO();
//        a.setAccNo("中国123123123");
//        a.setLogoPath("jasper/images/facAccLogo.jpg");
//        a.setDate("2018-01-01");
//
//        FacAccountPrintVO a1 = new FacAccountPrintVO();
//        a1.setAccNo("sssasdasdasdc啊啊从");
//        a.setLogoPath("jasper/images/facAccLogo.jpg");
//        //加入list
//        List<FacAccountPrintVO> beanList = new ArrayList<>();
//        beanList.add(a1);
//        beanList.add(a);
//
//        //临分免税账单pdf导出
//        String printPath = "C:\\Users\\Administrator\\Desktop\\最新v2\\test.pdf";
//        File  file = ReportUtil.savePdfByPath(printPath, new JasperReportVO(JasperModelEnum.FAC_ACC.getJasperPath(), beanList));
//
//        //临分应税账单(境外)pdf导出
//        String printPath2 = "C:\\Users\\Administrator\\Desktop\\最新v2\\test2.pdf";
//        File  file2 = ReportUtil.savePdfByPath(printPath2, new JasperReportVO(JasperModelEnum.FAC_ACC_OFFSHORE.getJasperPath(), beanList));
//
//        //临分应税账单(境内)pdf导出
//        String printPath3 = "C:\\Users\\Administrator\\Desktop\\最新v2\\test3.pdf";
//        File  file3 = ReportUtil.savePdfByPath(printPath3, new JasperReportVO(JasperModelEnum.FAC_ACC_ONSHORE.getJasperPath(), beanList));
    }


}
